package com.fansl.koala.quickdev.component;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.symmetric.AES;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import io.netty.buffer.ByteBufAllocator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.NettyDataBufferFactory;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author fansl
 * @Description: TODO
 * @date 2020/3/20 13:36
 */
@Slf4j
@Component
public class CustomWebFilter implements WebFilter {
    // 需要解密的请求header
    private static String DECRYPT_HEADER_VALUE = "level";
    private static final String KEY_ALGORITHM = "AES";

    @Value("${security.encode.key:1234567812345678}")
    private String encodeKey;

    private String decryptAES(String data, String encodeKey) {
        AES aes = new AES(Mode.CBC, Padding.NoPadding,
                new SecretKeySpec(encodeKey.getBytes(), KEY_ALGORITHM),
                new IvParameterSpec(encodeKey.getBytes()));
        byte[] result = aes.decrypt(Base64.decode(data.getBytes(StandardCharsets.UTF_8)));
        return new String(result, StandardCharsets.UTF_8);
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String decryptType = request.getHeaders().getFirst(DECRYPT_HEADER_VALUE);
        assert decryptType != null;
        if (StrUtil.isNotBlank(decryptType) && "1".equals(decryptType)) {
            URI uri = exchange.getRequest().getURI();
            String currentContentType = Objects.requireNonNull(request.getHeaders().getContentType()).toString();
            if (currentContentType.contains(MediaType.APPLICATION_JSON_VALUE)) {
                //json数据
                String bodyStr = resolveBodyFromRequest(request);
                String decryptBodyStr="";
                try {
                    log.info("加密的数据:{}", bodyStr);
                    decryptBodyStr = decryptAES( JSONObject.parseObject(bodyStr).getString("encrypt"), encodeKey).trim();
                    log.info("解密后的数据:{}", decryptBodyStr);
                }catch (Exception e){
                    log.error("解密数据失败:{}",bodyStr,e);
                }
                DataBuffer bodyDataBuffer = stringBuffer(decryptBodyStr);
                Flux<DataBuffer> bodyFlux = Flux.just(bodyDataBuffer);

                URI newUri = UriComponentsBuilder.fromUri(uri)
                        .build(true)
                        .toUri();
                ServerHttpRequest newRequest = exchange.getRequest().mutate().uri(newUri).build();
                ServerHttpRequestDecorator newRequestDecorator = new ServerHttpRequestDecorator(newRequest) {
                    @Override
                    public Flux<DataBuffer> getBody() {
                        return bodyFlux;
                    }
                };
                ServerWebExchange newExchange = exchange.mutate().request(newRequestDecorator).build();
                return chain.filter(newExchange);
            }
        }
        return chain.filter(exchange);
    }

    /**
     * 获取请求体中的字符串内容
     * @param serverHttpRequest request
     * @return string
     */
    private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest){
        //获取请求体
        Flux<DataBuffer> body = serverHttpRequest.getBody();
        StringBuilder sb = new StringBuilder();

        body.subscribe(buffer -> {
            byte[] bytes = new byte[buffer.readableByteCount()];
            buffer.read(bytes);
            DataBufferUtils.release(buffer);
            String bodyString = new String(bytes, StandardCharsets.UTF_8);
            sb.append(bodyString);
        });
        return sb.toString();

    }

    /**
     * 去掉空格,换行和制表符
     * @param str
     * @return
     */
    private String formatStr(String str){
        if (str != null && str.length() > 0) {
            Pattern p = Pattern.compile("\\s*|\t|\r|\n");
            Matcher m = p.matcher(str);
            return m.replaceAll("");
        }
        return str;
    }

    private DataBuffer stringBuffer(String value){
        byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
        NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
        DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
        buffer.write(bytes);
        return buffer;
    }

}
